from flask_socketio import join_room, leave_room, emit
from flask_jwt_extended import jwt_required, get_jwt_identity
from flask import request
from app.models import User, Channel, ServerMember, GuestUser
from app import db
from app.utils.response_utils import ResponseCode
from app.utils.security import socket_token_required
from app.services.message_service import MessageService
from collections import defaultdict

from threading import Lock



# 全局状态管理
onlineUsers = set()       # 存储非隐身在线用户ID
stealthUser = set()       # 存储隐身用户ID
active_connections = {}   # 存储连接信息: {socket_id: user_id}
connection_counts = {}    # 存储用户连接数: {user_id: count}
status_lock = Lock()      # 线程安全锁

voice_room_users = defaultdict(dict)

mySocketio = None

def register_socket_handlers(socketio):
    global mySocketio
    mySocketio = socketio  # 保存 socketio 实例

    def broadcast_user_status(socketio):
        onlineUserList = []
        stealthUserList = []
        for userid in onlineUsers:
            onlineUserList.append(userid)

        for userid in stealthUser:
            stealthUserList.append(userid)

        socketio.emit('broadcast_status', {
            'onlineUsers': onlineUserList,
            'stealthUser': stealthUserList,
        }, room=f'host')

    # 连接事件处理
    @socketio.on('connect')
    @socket_token_required
    def handle_connect(current_user_id,data):
        user_id = current_user_id
        sid = request.sid
        # 用户连接后，将其加入其所在的服务器房间
        user = User.query.get(user_id)
        if user is None:
            user = GuestUser.query.filter_by(guest_id=user_id).first()
        else:
            user.status = 'online'
        db.session.commit()
        with status_lock:
            # 更新连接计数
            connection_counts[user_id] = connection_counts.get(user_id, 0) + 1

            # 如果是首次连接
            if connection_counts[user_id] == 1:
                    onlineUsers.add(user_id)

            # 更新连接映射
            active_connections[sid] = user_id

        emit('connectSuccess')

        print(f'用户连接: {user_id}, 连接数: {connection_counts[user_id]}')
        print(f'当前在线: {onlineUsers}, 隐身用户: {stealthUser}')

    # 断开连接事件处理
    @socketio.on('disconnect')
    def handle_disconnect(data):
        sid = request.sid
        with status_lock:
            if sid not in active_connections:
                return

            user_id = active_connections.pop(sid)
            user = User.query.get(user_id)
            user_data = {
                'user_id': user.user_id,
                'username': user.username,
                'avatar_url': user.avatar_url
            }
            user.status = 'offline'
            db.session.commit()
            if user_id in connection_counts:
                # 减少连接计数
                connection_counts[user_id] -= 1

                # 如果是最后一个连接
                if connection_counts[user_id] == 0:
                    # 从用户列表中移除
                    if user_id in onlineUsers:
                        onlineUsers.remove(user_id)
                    if user_id in stealthUser:
                        stealthUser.remove(user_id)

                    # 清理计数器
                    del connection_counts[user_id]

            # 清理用户语音聊天
            for room_id, users in voice_room_users.items():
                if sid in users:
                    del users[sid]
                    emit('userLeft', {'user_id': user_id}, room=room_id)

        broadcast_user_status(socketio)
        print(f'用户断开: {user_id}, 剩余连接: {connection_counts.get(user_id, 0)}')
        print(f'当前在线: {onlineUsers}, 隐身用户: {stealthUser}')

    # 加入基础房间
    @socketio.on('join_host')
    def join_host():
        join_room('host')

        broadcast_user_status(socketio)

    # 添加心跳处理
    @socketio.on('ping')
    def handle_ping(data):
        print('sending pong')
        user_id = data.get('user_id')

        emit('pong')  # 立即回应心跳

        broadcast_user_status(socketio)

    # 加入频道房间
    @socketio.on('join_channel')
    @socket_token_required
    def handle_join_channel(current_user_id,data):
        user_id = current_user_id
        channel_id = data.get('channel_id')
        room_name = f'channel_{channel_id}'

        user = User.query.filter_by(user_id=user_id).first()
        if user is None:
            user = GuestUser.query.filter_by(guest_id=user_id).first()
            username = '游客'
        else:
            username = user.username


        join_room(room_name)
        broadcast_user_status(socketio)
        print(f'用户 {username} 加入频道 {room_name}')

    # 离开频道房间
    @socketio.on('leave_channel')
    def handle_leave_channel(data):
        channel_id = data.get('channel_id')
        user_id = data.get('user_id')
        room_name = f'channel_{channel_id}'

        user = User.query.filter_by(user_id=user_id).first()
        if user is None:
            user = GuestUser.query.filter_by(guest_id=user_id).first()
            username = '游客'
        else:
            username = user.username

        leave_room(room_name)
        print(f'用户 {username} 离开频道 {room_name}')

    @mySocketio.on('send_message')
    @socket_token_required
    def handle_send_message(current_user_id,data):
        """处理发送消息的Socket事件"""
        try:
            user_id = current_user_id
            content = data.get('content')
            channel_id = data.get('channel_id')

            if not content:
                emit('message_error', {'message': '消息内容不能为空'})
                return

            # 创建消息
            message = MessageService.create_channel_message(
                channel_id=channel_id,
                sender_id=user_id,
                content=content
            )

            if isinstance(message, tuple):  # 错误处理
                emit('message_error', {'message': message[0]})
                return

            myMessage = {
                'message_id': message.get('message_id'),
                'content': message.get('content'),
                'channel_id': message.get('channel_id'),
                'sender_id': message.get('sender_id'),
                'sender_name': message.get('sender_name'),
                'sender_avatar': message.get('sender_avatar'),
                'created_at': message.get('created_at').isoformat()
            }

            # 广播新消息
            mySocketio.emit('send_message_broadcast',myMessage , room=f'channel_{channel_id}')

            # 发送成功响应给发送者
            emit('send_message_success', myMessage)

        except Exception as e:
            emit('message_error', {'message': f'发送失败: {str(e)}'})


    # 加入频道房间
    @socketio.on('join_private')
    @socket_token_required
    def handle_join_private(current_user_id,data):
        user_id = current_user_id
        chat_id = data.get('chat_id')

        user = User.query.filter_by(user_id=user_id).first()
        if user is None:
            user = GuestUser.query.filter_by(guest_id=user_id).first()
            username = '游客'
        else:
            username = user.username


        join_room(f'private_{chat_id}')
        broadcast_user_status(socketio)
        print(f'用户 {username} 加入私聊 {chat_id}')

    # 离开频道房间
    @socketio.on('leave_private')
    def handle_leave_private(data):
        chat_id = data.get('chat_id')
        user_id = data.get('user_id')

        user = User.query.filter_by(user_id=user_id).first()
        if user is None:
            user = GuestUser.query.filter_by(guest_id=user_id).first()
            username = '游客'
        else:
            username = user.username

        leave_room(f'private_{chat_id}')
        print(f'用户 {username} 离开私聊 {chat_id}')

    @mySocketio.on('send_private_message')
    @socket_token_required
    def handle_send_private_message(current_user_id,data):
        """处理发送消息的Socket事件"""
        try:
            user_id = current_user_id
            content = data.get('content')
            chat_id = data.get('chat_id')

            if not content:
                emit('message_error', {'message': '消息内容不能为空'})
                return

            # 创建消息
            message = MessageService.create_direct_message(
                direct_chat_id=chat_id,
                sender_id=user_id,
                content=content
            )

            if isinstance(message, tuple):  # 错误处理
                emit('message_error', {'message': message[0]})
                return

            myMessage = {
                'message_id': message.get('message_id'),
                'content': message.get('content'),
                'chat_id': message.get('chat_id'),
                'sender_id': message.get('sender_id'),
                'sender_name': message.get('sender_name'),
                'sender_avatar': message.get('sender_avatar'),
                'created_at': message.get('created_at').isoformat()
            }

            # 广播新消息
            mySocketio.emit('send_message_broadcast',myMessage , room=f'private_{chat_id}')

            # 发送成功响应给发送者
            emit('send_message_success', myMessage)

        except Exception as e:
            emit('message_error', {'message': f'发送失败: {str(e)}'})

    @mySocketio.on('delete_message')
    @socket_token_required
    def handle_delete_message(current_user_id,data):
        """处理删除消息的Socket事件"""
        try:
            user_id = current_user_id
            message_id = data.get('message_id')

            if not message_id:
                emit('message_error', {'message': '消息ID不能为空'})
                return

            result = MessageService.delete_message(
                message_id=message_id,
                user_id=user_id
            )

            if isinstance(result, tuple):  # 错误处理
                emit('message_error', {'message': result[0]})
                return

            # 广播删除事件
            mySocketio.emit('delete_message_broadcast', {
                'message_id': result['message_id'],
                'channel_id': result['channel_id']
            }, room=f'channel_{result["channel_id"]}')

            # 发送成功响应给发起者
            emit('delete_message_success', {'message_id': message_id})

        except Exception as e:
            emit('message_error', {'message': f'删除失败: {str(e)}'})

    @mySocketio.on('delete_private_message')
    @socket_token_required
    def handle_delete_private_message(current_user_id,data):
        """处理删除消息的Socket事件"""
        try:
            user_id = current_user_id
            message_id = data.get('message_id')

            if not message_id:
                emit('message_error', {'message': '消息ID不能为空'})
                return

            result = MessageService.delete_message(
                message_id=message_id,
                user_id=user_id
            )

            if isinstance(result, tuple):  # 错误处理
                emit('message_error', {'message': result[0]})
                return
            # 广播删除事件
            mySocketio.emit('delete_message_broadcast', {
                'message_id': result['message_id'],
                'direct_chat_id': result['direct_chat_id']
            }, room=f'private_{result["direct_chat_id"]}')

            # 发送成功响应给发起者
            emit('delete_message_success', {'message_id': message_id})

        except Exception as e:
            emit('message_error', {'message': f'删除失败: {str(e)}'})

    # 修改用户状态
    @mySocketio.on('change_user_status')
    @socket_token_required
    def change_user_status(current_user_id,data):
        user_id = current_user_id
        status = data.get('status')
        print(status)
        user = User.query.get(user_id)
        user.status = status
        db.session.commit()

        if status == 'idle':
            onlineUsers.remove(user_id)
            stealthUser.add(user_id)
        elif status == 'online':
            stealthUser.remove(user_id)
            onlineUsers.add(user_id)

        broadcast_user_status(socketio)

    @socketio.on('join_voice_channel')
    @socket_token_required
    def join_voice_channel(current_user_id, data):
        user_id = current_user_id
        room_name = f'voiceChannel_{data["channel_id"]}'
        user = User.query.filter_by(user_id=user_id).first()

        join_room(room_name)
        print(f'用户 {user.username} 加入语音频道 {room_name}')
        # 给新加入者发送当前用户列表
        users_in_room = list(voice_room_users[f'voiceRoom_{data["channel_id"]}'].values())
        emit('sendChatUsers', {'users': users_in_room}, room=room_name)

    @socketio.on('leave_voice_channel')
    def leave_voice_channel(data):
        user_id = data['user_id']
        room_name = f'voiceChannel_{data["channel_id"]}'

        user = User.query.filter_by(user_id=user_id).first()
        leave_room(room_name)

        print(f'用户 {user.username} 离开语音频道 {room_name}')


    # 加入语音房间
    @socketio.on('join_voice_chat')
    @socket_token_required
    def join_voice_channel(current_user_id,data):
        user_id = current_user_id
        room_name = f'voiceRoom_{data["channel_id"]}'

        user = User.query.filter_by(user_id=user_id).first()
        user_data = {
            'user_id': user.user_id,
            'username': user.username,
            'avatar_url': user.avatar_url
        }

        join_room(room_name)
        print(f'用户 {user.username} 加入语音房间 {room_name}')

        # 保存用户
        if room_name not in voice_room_users:
            voice_room_users[room_name] = {}

        # 添加到跟踪字典
        voice_room_users[room_name][request.sid] = user_data
        # 发送当前用户列表给所有人
        users_in_room = list(voice_room_users[room_name].values())
        emit('usersChange',{'user':user_data,'type':'join'},room=f'voiceChannel_{data["channel_id"]}')
        emit('userJoined', {'user_id':user.user_id}, room=room_name, skip_sid=request.sid)

    # 离开语音房间
    @socketio.on('leave_voice_chat')
    def handle_leave_channel(data):
        user_id = data.get('user_id')
        room_name = f'voiceRoom_{data["channel_id"]}'

        user = User.query.filter_by(user_id=user_id).first()
        user_data = {
            'user_id': user.user_id,
            'username': user.username,
            'avatar_url': user.avatar_url
        }

        leave_room(room_name)
        print(f'用户 {user.username} 离开语音房间 {room_name}')
        for room_id, users in voice_room_users.items():
            if request.sid in users:
                del users[request.sid]
                emit('userLeft', {'user_id': user_id}, room=room_id)
                emit('usersChange', {'user': user_data, 'type': 'leave'}, room=f'voiceChannel_{data["channel_id"]}')



    # 添加ICE候选转发方法
    @socketio.on('sendOffer')
    @socket_token_required
    def handle_send_offer(current_user_id,data):
        room_name = f'voiceRoom_{data["channel_id"]}'
        emit('onOffer', {
            'offer': data['offer'],
            'from_user_id': current_user_id
        }, room=room_name)

    @socketio.on('sendAnswer')
    @socket_token_required
    def handle_send_answer(current_user_id,data):
        room_name = f'voiceRoom_{data["channel_id"]}'
        emit('onAnswer', {
            'answer': data['answer'],
            'from_user_id': current_user_id
        }, room=room_name)

    @socketio.on('sendIceCandidate')
    @socket_token_required
    def handle_send_ice_candidate(current_user_id,data):
        room_name = f'voiceRoom_{data["channel_id"]}'
        emit('onIceCandidate', {
            'candidate': data['candidate'],
            'from_user_id': current_user_id
        }, room=room_name)




# 广播新消息
def broadcast_new_message(message):
    from flask_socketio import emit
    channel_id = message.get('channel_id')

    # 广播到整个频道
    if mySocketio:
        mySocketio.emit('new_message', {
                'message_id': message.get('message_id'),
                'content': message.get('content'),
                'channel_id': message.get('channel_id'),
                'sender_id': message.get('sender_id'),
                'sender_name': message.get('sender_name'),
                'sender_avatar': message.get('sender_avatar'),
                'created_at': message.get('created_at').isoformat()
            }, room=f'channel_{channel_id}')

def broadcast_delete_message(message):
    from flask_socketio import emit
    channel_id = message.get('channel_id')

    if mySocketio:
        mySocketio.emit('delete_message',message.get('message_id'),room=f'channel_{channel_id}')
